package com.fuyin.service.user.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;

import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.fuyin.commons.enums.ErrorCodeEnum;
import com.fuyin.commons.response.BaseResponse;
import com.fuyin.commons.response.ErrorCode;
import com.fuyin.commons.utils.JwtTokenUtil;
import com.fuyin.commons.utils.MyUtils;
import com.fuyin.dao.GpDao;
import com.fuyin.dao.ReportDao;
import com.fuyin.dao.UserDao;
import com.fuyin.dto.CommonUserDetails;
import com.fuyin.dto.params.LoginParam;
import com.fuyin.dto.vo.LoginResult;
import com.fuyin.entity.PmValidate;
import com.fuyin.entity.ReportInfo;
import com.fuyin.entity.User;
import com.fuyin.service.RedisService;
import com.fuyin.service.ValidateServiceImpl;
import com.fuyin.service.user.UserService;
import com.github.pagehelper.PageHelper;

import cn.hutool.core.lang.Validator;
import lombok.extern.slf4j.Slf4j;

/**
 * @author yuanxilan (yuanxilan@keep.com)
 * @Description
 * @date 2021年10月23日 3:41 下午
 * @since
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserDao userDao;

    @Autowired
    private ReportDao reportDao;

    @Autowired
    private GpDao gpDao;

    @Autowired
    private RedisService redisService;

    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Autowired
    private ValidateServiceImpl validateService;

    //发送邮件的类
    @Autowired
    private JavaMailSender mailSender;

    //这里使用的是我们已经在配置问价中固定了的变量值,也就是通过这个邮箱向目标邮箱发送重置密码的邮件
    @Value("${spring.mail.username}")
    private String from;

    @Value("${password.pattern}")
    private String passwordPattern;

    private static final String ip = "http://120.77.71.117:8076";

    @Override
    public BaseResponse login(LoginParam param) {
        if (Objects.isNull(param) || StringUtils.isBlank(param.getUserName()) || StringUtils.isBlank(param.getPassword())) {
            log.error("com.fuyin.service.user.impl.UserServiceImpl#login param:{}", param);
            return BaseResponse.error(ErrorCodeEnum.BAD_REQUEST);
        }
        String token = "";
        User user = userDao.getUserByUserName(param.getUserName());
        if (Objects.isNull(user)) {
            return BaseResponse.error(ErrorCode.ACCOUNT_NOT_FOUND, "账号不存在");
        } else if (user.getState() == -1) {
            return BaseResponse.error(ErrorCode.ACCOUNT_NOT_USED, "账号未启动");
        } else if (!passwordEncoder.matches(param.getPassword(), user.getPassword())) {
            return BaseResponse.error(ErrorCode.ACCOUNT_ERROR, "账号密码错误");
        } else if (user.getType() != 0) {
            return BaseResponse.error(ErrorCode.FORBIDDEN, "非用户请求用户接口");
        }
        if (redisService.exists(user.getUserName())) {
            redisService.delete(redisService.get(user.getUserName()));
        }
        CommonUserDetails userDetails = new CommonUserDetails(user);
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        token = jwtTokenUtil.generateToken(userDetails);
        redisService.set(token, user.getType());
        redisService.set(user.getUserName(), token);
        return BaseResponse.success(new LoginResult(token, user.getType()));
    }

    @Override
    public BaseResponse register(LoginParam param, HttpServletRequest request) {
        if (Objects.isNull(param) || StringUtils.isBlank(param.getUserName()) || StringUtils.isBlank(param.getPassword()) || StringUtils.isBlank(param.getEmail())) {
            log.error("com.fuyin.service.user.impl.UserServiceImpl#register param:{}", param);
            return BaseResponse.error(ErrorCodeEnum.BAD_REQUEST);
        }
        User user = userDao.getUserByUserName(param.getUserName());
        if (Objects.nonNull(user)) {
            return BaseResponse.error(ErrorCode.REPEAT_REGISTER, "重复注册");
        }
        user = userDao.getUserByEmail(param.getEmail());
        if (Objects.nonNull(user)) {
            return BaseResponse.error(ErrorCode.EMAIL_USED, "邮箱已被注册");
        }
        if (!param.getPassword().matches(passwordPattern) || Validator.hasChinese(param.getPassword())) {
            return BaseResponse.error(ErrorCode.PASSWORD_NOT_MATCH_PATTERN, "密码不符合规范");
        }
        String encodePassword = passwordEncoder.encode(param.getPassword());
        user = new User(param.getUserName(), encodePassword, param.getEmail(), 0, 0);

        String email = param.getEmail();
        try {
            if (validateService.sendValidateLimitation(email, 20, 1)) {
                // 若允许重置密码，则在pm_validate表中插入一行数据，带有token
                PmValidate pmValidate = new PmValidate();
                validateService.insertNewResetRecord(pmValidate, user, UUID.randomUUID().toString(), "register");
                // 设置邮件内容
                String appUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/fuyin/api/saveAccount";
                MimeMessage mimeMessage = mailSender.createMimeMessage();
                // multipart模式
                MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, true, "utf-8");
                mimeMessageHelper.setTo(email);
                mimeMessageHelper.setFrom(from);
                mimeMessageHelper.setSubject("注册账号");
                StringBuilder sb = new StringBuilder();
                sb.append("<html><head></head>");
                sb.append("<body><h1>点击下面的链接确认注册，有效期为 5 分钟</h1>" +
                        "<a href = " + appUrl + "?token=" + pmValidate.getResetToken() + ">" + appUrl + "?token=" + pmValidate.getResetToken() + "</a></body>");
                sb.append("</html>");
                // 启用html
                mimeMessageHelper.setText(sb.toString(), true);
                validateService.sendPasswordResetEmail(mimeMessage);
                redisService.set(pmValidate.getResetToken(), user);
            } else {
                return BaseResponse.error(ErrorCode.OPERATION_FREQUENCY, "操作过于频繁，请稍后再试！");
            }
        } catch (Exception e) {
            log.error("com.fuyin.service.user.impl.UserServiceImpl.register e:{}", e.getMessage());
        }
//        userDao.register(user);
        return BaseResponse.success();
    }

    @Override
    public UserDetails loadUserByUsername(String userName) {
        User user = userDao.getUserByUserName(userName);
        if (Objects.nonNull(user)) {
            return new CommonUserDetails(user);
        }
        return null;
    }

    @Override
    public User getUserByUserName(String userName) {
        if (StringUtils.isBlank(userName)) {
            return null;
        }
        return userDao.getUserByUserName(userName);
    }

    @Override
    public BaseResponse<ArrayList<User>> test(Integer pageNum, Integer pageSize) {
        log.info("pageNum: {}, pageSize: {}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        return BaseResponse.success((ArrayList<User>) userDao.getUserList(Arrays.asList(0)));
    }

    @Override
    public BaseResponse logout(String token) {
        token = StringUtils.substring(token, tokenHead.length());
        redisService.delete(token);
        return BaseResponse.success();
    }

    @Override
    public BaseResponse updatePasswordByOldPassword(String userName, String oldPassword, String newPassword) {
        MyUtils.checkParams("账号、旧密码、新密码不能为空", userName, oldPassword, newPassword);
        if (oldPassword.equals(newPassword)) {
            return BaseResponse.error(ErrorCode.ACCOUNT_NEW_OLD_PSW_SAME, "新密码不能与旧密码相同");
        }
        User user = userDao.getUserByUserName(userName);
        if (Objects.isNull(user)) {
            return BaseResponse.error(ErrorCode.ACCOUNT_NOT_FOUND, "账号不存在");
        } else if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            return BaseResponse.error(ErrorCode.ACCOUNT_ERROR, "账号密码错误");
        }
        if (!newPassword.matches(passwordPattern) || Validator.hasChinese(newPassword)) {
            return BaseResponse.error(ErrorCode.PASSWORD_NOT_MATCH_PATTERN, "新密码不符合规范");
        }
        newPassword = passwordEncoder.encode(newPassword);
        userDao.updatePassword(userName, newPassword);
        if (redisService.exists(userName)) {
            redisService.delete(redisService.get(userName));
            redisService.delete(userName);
        }
        return BaseResponse.success();
    }

    @Override
    @Deprecated
    public BaseResponse updatePasswordByHobby(String userName, String password, String hobby) {
        MyUtils.checkParams("账号、新密码、爱好不能为空", userName, password, hobby);
        password = passwordEncoder.encode(password);
        User user = userDao.getUserByUserName(userName);
        if (Objects.isNull(user)) {
            return BaseResponse.error(ErrorCodeEnum.BAD_REQUEST.getErrorCode(), "账号不存在");
        } else if (!StringUtils.equals(hobby, user.getHobby())) {
            return BaseResponse.error(ErrorCodeEnum.BAD_REQUEST.getErrorCode(), "爱好填写错误");
        }
        userDao.updatePassword(userName, password);
        if (redisService.exists(userName)) {
            redisService.delete(redisService.get(userName));
            redisService.delete(userName);
        }
        return BaseResponse.success();
    }

    @Override
    public BaseResponse<ArrayList<ReportInfo>> getReportInfo(String token, Integer pageSize, Integer pageNum, Integer type) {
        MyUtils.checkParams("pageSize 和 pageNum 不能为空", pageSize, pageNum);
        if (pageSize <= 0 || pageNum <= 0) {
            return BaseResponse.error(ErrorCode.BAD_REQUEST, "pageNum 和 pageSize 不能小于 0");
        }
        String userName = jwtTokenUtil.getUserNameFromToken(token.substring(this.tokenHead.length()));
        if (StringUtils.isBlank(userName)) {
            return BaseResponse.error(ErrorCode.UNAUTHORIZED, "token 失效，请重新登录");
        }
        User user = userDao.getUserByUserName(userName);
        if (Objects.isNull(user)) {
            return BaseResponse.error(ErrorCode.ACCOUNT_NOT_FOUND, "账号不存在");
        }
        PageHelper.startPage(pageNum, pageSize);
        ArrayList<ReportInfo> reportInfos = (ArrayList<ReportInfo>) reportDao.getReportInfosByUserIdAndType(user.getId(), type);
        for (ReportInfo reportInfo : reportInfos) {
//            String replaceText = reportInfo.getInfo().replaceAll("\\\\","");
//            String parseText = replaceText.substring(1,replaceText.length()-1);
//            Object parse = JSONObject.parse(reportInfo.getInfo());
//            log.info("parse: {}", parse);
//            String sJsonOne = parse.toString();
//            reportInfo.setReport(JSON.parseObject(sJsonOne, RiskReport.class));
//            reportInfo.setReport(JSON.parseObject(StringEscapeUtils.unescapeJava(JSON.toJSONString(reportInfo.getInfo())), RiskReport.class));
//            reportInfo.setReport(JSON.parseObject(parse, RiskReport.class));
//            reportInfo.setReport(JSONObject.parseObject(JSON.parse(reportInfo.getInfo()).toString(), RiskReport.class));
//            reportInfo.setReport(reportInfo);
            try {
                reportInfo.setReport(MyUtils.byteToObj(reportInfo.getInfo()));
                reportInfo.setInfo(new byte[]{});
            } catch (Exception e) {
                log.error("com.fuyin.service.user.impl.UserServiceImpl.getReportInfo e:{}, user:{}", e.getMessage(), user);
            }
        }
        return BaseResponse.success(reportInfos);
    }

    @Override
    public User findUserByEmail(String email) {
        if (StringUtils.isBlank(email)) {
            log.error("com.fuyin.service.user.impl.UserServiceImpl.findUserByEmail email is null");
            return new User();
        }
        return userDao.getUserByEmail(email);
    }

    @Override
    public String saveAccount(String token) {
        User user = redisService.get(token, User.class);
        log.info("com.fuyin.service.user.impl.UserServiceImpl.saveAccount user: {}", user);
        if (Objects.isNull(user)) {
            return "redirect:" + ip + "/register_feedback?register_result=0";
        }
        redisService.delete(token);
        userDao.register(user);
        return "redirect:" + ip + "/register_feedback?register_result=1";
    }

    @Override
    public String changeEmail(String token) {
        User user = redisService.get(token, User.class);
        if (Objects.isNull(user)) {
            return "redirect:" + ip + "/update_email_feedback?result=0";
        }
        redisService.delete(token);
        user.setPassword("");
        user.setType(null);
        user.setState(null);
        user.setHobby(null);
        userDao.updateUser(user);
        return "redirect:" + ip + "/update_email_feedback?result=1";
    }

    @Override
    public BaseResponse<User> getUserInfo(String token) {
        token = token.substring(this.tokenHead.length());
        String userName = jwtTokenUtil.getUserNameFromToken(token);
        User user = userDao.getUserByUserName(userName);
        user.setPassword("");
        return BaseResponse.success(user);
    }


//    @Override
//    public List<Resource> getResourceList(Long userId) {
//        return userDao.getResourceList(userId);
//    }
}
